package com.ajk.server.utils;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.UUID;

import javax.crypto.KeyGenerator;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;

import com.ajk.server.dao.AjkAccountMapper;
import com.ajk.server.model.AjkAccount;

public class CryptoUtil {

    private static Logger logger = LoggerFactory.getLogger(CryptoUtil.class);

    private static final String LEGACY_MD5_ENCODE_KEY = "jsiuewiu6%&*&8fjkaklsalsd38%^fha";

    private static Environment env;
    private static AjkAccountMapper ajkAccountMapper;
    
    private static String[] hexDigits = new String[]
    		{"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};  

    private static String[] DEFAULT_NAME_CHAR_ARRAY = new String [] {
        "A","B","C","D","E","F","G","H","I","G","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
        "a","b","c","d","e","f","g","h","i","g","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};

    public static String generateRandStr(int n) {

        StringBuilder verificationCode = new StringBuilder();

        Random rand = new Random();

        for (int i = 0; i < n; i++) {
            verificationCode.append(rand.nextInt(10));

        }

        return verificationCode.toString();
    }

    public static String generateRandName(int n) {

        StringBuilder name = new StringBuilder();

        Random rand = new Random();

        for (int i = 0; i < n; i++) {
            name.append(DEFAULT_NAME_CHAR_ARRAY[rand.nextInt(52)]);
        }

        return name.toString();
    }

    public static String generateBase64EncodedRandomProperty(int length)
            throws
            NoSuchAlgorithmException {

        String algorithm = env.getProperty("config.encoded_algorithm");
        KeyGenerator keyGen = KeyGenerator.getInstance(algorithm);
        keyGen.init(length);
        byte[] property = keyGen.generateKey().getEncoded();
        return Base64.encodeBase64String(property);
    }

    public static String MD5Encode(byte[] password) throws NoSuchAlgorithmException {

        StringBuilder sb = new StringBuilder();

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] encoded = md.digest(password);
        for (byte b : encoded) {
            sb.append(Integer.toHexString(0xFF & b));
        }

        return sb.toString();
    }

    public final static String legacyMD5Encode(byte[] password) throws NoSuchAlgorithmException {
        char hexDigits[] = { '0', '1', '2', '3', '4',
            '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F' };

        MessageDigest mdInst = MessageDigest.getInstance("MD5");
        mdInst.update(LEGACY_MD5_ENCODE_KEY.getBytes());
        mdInst.update(password);
        byte[] md = mdInst.digest();
        int len = md.length;
        char str[] = new char[len * 2];
        int j = 0;
        for (int i = 0; i < len; i++) {
            byte byte0 = md[i];
            str[j++] = hexDigits[byte0 >>> 4 & 0xf];
            str[j++] = hexDigits[byte0 & 0xf];
        }
        return new String(str);
    }

 
    public static String generateUniqueAccessId() throws Exception {

        Boolean isUnique = false;
        String accessId = null;
        AjkAccount userDetails;

        while (!isUnique) {
        	accessId = UUID.randomUUID().toString();
            userDetails = ajkAccountMapper.findByAccessId(accessId);

            if (userDetails != null) {
                continue;
            }

            isUnique = true;
        }

        return accessId;
    }

    public static String generateUniqueAccessKey() throws Exception {
        boolean isUnique = false;
        String accessKey = null;

        AjkAccount userDetails;

        while (!isUnique) {
            try {
                accessKey = CryptoUtil.generateBase64EncodedRandomProperty(240);
            } catch (NoSuchAlgorithmException e) {
                throw new PersistenceException(e);
            }

            userDetails = ajkAccountMapper.findByAccessKey(accessKey);

            if (userDetails != null) {
                continue;
            }

            isUnique = true;
        }

        return accessKey;
    }

    public void setEnv(Environment env) {
    	CryptoUtil.env = env;
    }
    public void setAjkAccountMapper(AjkAccountMapper ajkAccountMapper) {
		CryptoUtil.ajkAccountMapper = ajkAccountMapper;
	}
    
    public static Map<String, String> sortMapByKey(Map<String, String> oriMap) {  
        if (oriMap == null || oriMap.isEmpty()) {  
            return null;  
        }  
        Map<String, String> sortedMap = new TreeMap<String, String>();
        sortedMap.putAll(oriMap);
        return sortedMap;  
    } 
    
    public static Integer compareString(String s1,String s2){
    	char c1;
    	char c2;
    	Integer length1=s1.length();
    	Integer length2=s2.length();
    	int length=length1>length2?length2:length1;
    	if(length>0){
	    	for(int i=0;i<length;i++){
	    		c1=s1.charAt(i);
	    		c2=s2.charAt(i);
	    		if(c1>c2){
	    			return 1;
	    		}else if(c1<c2){
	    			return 0;
	    		}else{
	    			continue;
	    		}	
	    	}
    	}
    	return 1;
    }
    
  public  static String encodeByMD5(String originstr)  
         {  
             if(originstr !=null)  
            {  
                 try{  
                   //创建具有指定算法名称的信息摘要   
                    MessageDigest md = MessageDigest.getInstance("MD5");  
                     //使用指定的字节数组对摘要进行最后的更新，然后完成摘要计算   
                     byte[] results = md.digest(originstr.getBytes());  
                      //将得到的字节数组编程字符窜返回   
                     String resultString = byteArrayToHexString(results);  
                     return resultString.toUpperCase();  
                 }catch(Exception ex){  
                     ex.printStackTrace();  
                 }  
             }  
            return null;  
         }  
    
  		//转换字节数组为十六进制字符串   
         private static String byteArrayToHexString(byte[] b)  
        {  
            StringBuffer resultsb = new StringBuffer();  
            int i=0;  
            for(i=0;i<b.length;i++)  
            {  
                resultsb.append(byteToHexString(b[i]));  
            }  
            return resultsb.toString();  
        }  
         
       //将字节转化成十六进制的字符串   
        private static String byteToHexString(byte b)  
             {  
                int n=b;  
                if(n<0)  
                 {  
                     n = 256 + n;  
                 }  
                 int d1 = n / 16;  
                 int d2 = n /16;  
                 return hexDigits[d1]+hexDigits[d2];  
             }
        
        
        /** 
         * md5或者sha-1加密 
         *  
         * @param inputText 
         *            要加密的内容 
         * @param algorithmName 
         *            加密算法名称：md5或者sha-1，不区分大小写 
         * @return 
         */  
       public static String encrypt(String inputText, String algorithmName) {  
            if (inputText == null || "".equals(inputText.trim())) {  
                throw new IllegalArgumentException("请输入要加密的内容");  
            }  
            if (algorithmName == null || "".equals(algorithmName.trim())) {  
                algorithmName = "md5";  
            }  
            String encryptText = null;  
            try {  
                MessageDigest m = MessageDigest.getInstance(algorithmName);  
                m.update(inputText.getBytes("UTF8"));  
                byte s[] = m.digest();  
                // m.digest(inputText.getBytes("UTF8"));  
                return hex(s);  
            } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
            } catch (UnsupportedEncodingException e) {  
                e.printStackTrace();  
            }  
            return encryptText;  
        }  
      
        // 返回十六进制字符串  
        private static String hex(byte[] arr) {  
            StringBuffer sb = new StringBuffer();  
            for (int i = 0; i < arr.length; ++i) {  
                sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1,  
                        3));  
            }  
            return sb.toString();  
        } 
        
}